<?php
/**
 * Inter组件之Session操作器：session原生操作器。
 * 本类将所有内容存储在$_SESSION下
 * 支持自行使用$_SESSION数组完成对session的操作。
 * 
 * @author Horse Luke<horseluke@126.com>
 * @copyright Horse Luke, 2010
 * @license the Apache License, Version 2.0 (the "License"). {@link http://www.apache.org/licenses/LICENSE-2.0}
 * @version $Id: Native.php 158 2011-02-04 16:14:12Z horseluke@126.com $
 * @package Inter_Session
 * @subpackage Inter_Session_Operator
 *
 */
class Inter_Session_Operator_Native extends Inter_Session_Operator_Abstract{
    
    /**
     * 存储Inter_Session_Storage_Abstract。
     * 解决当让php原生操作Session+使用兼容存储方案后，
     * 在session_start后紧接着session_destroy或session_write_close等，
     * 再调用session_start时，会产生如下错误：
     * fatal error: session_start(): Failed to initialize storage module: user (path: ) ...
     * @var Inter_Session_Storage_Abstract
     */
    protected $_storageHandler = null;
    
    /**
     * 启动session_start次数？
     * @var integer
     */
    protected $_startCount = 0;
    
    /**
     * 构造方法
     * @return Inter_Session_Operator_Native
     */
    public function __construct(){
    }
    
    /**
     * 注册一个session存储器实例。
     * 本类模仿session_set_save_handler
     * 对于本原生操作器来讲，这个为可选方法，并且要在本类的session_start之前启动。
     * @param Inter_Session_Storage_Abstract &$handler 一个session存储器实例
     * @return bool
     */
    public function setStorageHandler(&$handler){
        if(!$handler instanceof Inter_Session_Storage_Abstract) {
        	throw new Exception('The handler is not instance of Inter_Session_Storage_Abstract');
        }
        $this->_storageHandler =& $handler;
        $this->_register();
        return true;
    }
    
    /**
     * 清除session
     */
    public function clear(){
        $_SESSION = array();
    }
    
    /**
     * 设置session
     * @param mixed $k 如果传入数组，则表示批量设置
     * @param mixed $v
     */
    public function set($k,$v=false){
        if( is_array($k) ){
            $_SESSION = array_merge($_SESSION,$k);
        }else{
            $_SESSION[$k] = $v;
        }
    }
    
    /**
     * 获取session
     * @param string|null $key 如果留空，则表示返回整个session
     * @return mixed
     */
    public function get($key = null){
        if( null !==  $key ){
            return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
        }else{
            return $_SESSION;
        }
    }
    
    /**
     * 删除某个/某组session
     * @param mixed $k 如果传入数组，则表示批量删除
     * @return bool
     */
    public function del($k){
        if ( empty($_SESSION) ){
            return true;
        }
        if(!is_array($k)){
            $k = array($k);
        }
        foreach( $k as $kv ){
            if (isset($_SESSION[$kv])){
                unset($_SESSION[$kv]);
            }
        }
        return true;
    }
    
    /**
     * 模拟php函数session_start，启动session机制。
     * @return bool
     */
    public function session_start(){
        //@see Inter_Session_Operator_Native::_storageHandler
        if(null !== $this->_storageHandler && $this->_startCount > 0){
            $this->_register();
        }
        $this->_startCount++;
        return session_start();
    }
    
    /**
     * 魔术方法调用session函数
     * @param string $method
     * @param array $param
     */
    public function __call($method, $param){
        if(0 !== strpos($method, 'session_')){
            throw new Exception('Unexpected session method:'. $method);
        }
        return call_user_func_array($method, $param);
    }
    
    /**
     * 获取session的相关设置
     * 直接调取ini_get获取
     * @param mixed $name 必须要传入参数，否则将返回空数组
     * @return mixed
     */
    public function getConfig($name=null){
        if(empty($name)){
            return ini_get_all('Session');
        }else{
            return ini_get($name);
        }
    }
    
    /**
     * 将{@link Inter_Session_Operator_Native::_storageHandler}注册到php session处理堆栈中
     */
    protected function _register(){
        return session_set_save_handler(
            array(&$this->_storageHandler, "open"), 
            array(&$this->_storageHandler, "close"), 
            array(&$this->_storageHandler, "read"), 
            array(&$this->_storageHandler, "write"),
            array(&$this->_storageHandler, "destroy"),
            array(&$this->_storageHandler, "gc")
        );
    }
    
}